// ============================================
// 05 - 所有权 (Ownership)
// ============================================

/// 所有权是 Rust 最独特的特性
/// 它使 Rust 无需垃圾回收器就能保证内存安全

// ==================== 所有权规则 ====================
// 1. Rust 中的每个值都有一个所有者 (owner)
// 2. 值在任一时刻有且只有一个所有者
// 3. 当所有者离开作用域，这个值将被丢弃

/// 变量作用域
pub fn variable_scope() {
    println!("\n=== 变量作用域 ===");
    
    {
        // s 在这里无效，它尚未声明
        let s = "hello"; // 从此处起，s 有效
        println!("字符串 s: {}", s);
        // 使用 s
    } // 此作用域结束，s 不再有效
    
    println!("s 已经离开作用域，无法再使用");
}

/// String 类型
/// String 类型在堆上分配内存，可以存储编译时未知大小的文本
pub fn string_type() {
    println!("\n=== String 类型 ===");
    
    // 从字符串字面量创建 String
    let mut s = String::from("hello");
    println!("初始 String: {}", s);
    
    // String 可以修改
    s.push_str(", world!");
    println!("修改后: {}", s);
    
    // 字符串字面量 vs String
    let s1 = "hello"; // &str - 不可变，固定大小
    let s2 = String::from("hello"); // String - 可变，可增长
    println!("字符串字面量: {}, String: {}", s1, s2);
}

/// 移动 (Move)
/// 当值的所有权转移时，旧的变量失效
pub fn move_semantics() {
    println!("\n=== 移动语义 ===");
    
    // 整数的复制
    let x = 5;
    let y = x; // 整数实现了 Copy trait，所以是复制
    println!("整数复制: x = {}, y = {}", x, y);
    
    // String 的移动
    let s1 = String::from("hello");
    let s2 = s1; // s1 的所有权移动到 s2
    println!("String 移动: s2 = {}", s2);
    // println!("s1 = {}", s1); // ❌ 错误: s1 已失效
    
    // 解释移动
    println!("\n移动发生时:");
    println!("  1. s2 获得了所有权");
    println!("  2. s1 不再有效");
    println!("  3. 避免了双重释放 (double free)");
}

/// 克隆 (Clone)
/// 深度复制堆上的数据
pub fn clone_data() {
    println!("\n=== 克隆数据 ===");
    
    let s1 = String::from("hello");
    let s2 = s1.clone(); // 深度复制
    
    println!("s1 = {}, s2 = {}", s1, s2);
    println!("克隆会复制堆上的数据，可能开销较大");
}

/// Copy trait
/// 简单标量值可以实现 Copy trait
pub fn copy_trait() {
    println!("\n=== Copy trait ===");
    
    // 以下类型实现了 Copy trait:
    let a = 5;
    let b = a;
    println!("整数: a = {}, b = {}", a, b);
    
    let x = true;
    let y = x;
    println!("布尔值: x = {}, y = {}", x, y);
    
    let c1 = 'a';
    let c2 = c1;
    println!("字符: c1 = {}, c2 = {}", c1, c2);
    
    let t1 = (1, 2.0);
    let t2 = t1;
    println!("元组: t1 = {:?}, t2 = {:?}", t1, t2);
}

/// 所有权与函数
/// 将值传递给函数会移动或复制所有权
pub fn ownership_and_functions() {
    println!("\n=== 所有权与函数 ===");
    
    let s = String::from("hello");
    takes_ownership(s); // s 的所有权移动到函数里
    // println!("{}", s); // ❌ 错误: s 已失效
    
    let x = 5;
    makes_copy(x); // x 实现了 Copy，传递的是副本
    println!("x 仍然有效: {}", x); // ✅ 可以继续使用 x
}

fn takes_ownership(some_string: String) {
    println!("函数获得所有权: {}", some_string);
} // some_string 在这里被丢弃

fn makes_copy(some_integer: i32) {
    println!("函数收到副本: {}", some_integer);
}

/// 返回值与所有权
/// 返回值可以转移所有权
pub fn return_values_and_ownership() {
    println!("\n=== 返回值与所有权 ===");
    
    let s1 = gives_ownership();
    println!("获得所有权: {}", s1);
    
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2);
    // println!("{}", s2); // ❌ 错误: s2 已失效
    println!("重新获得所有权: {}", s3);
}

fn gives_ownership() -> String {
    let some_string = String::from("yours");
    some_string // 返回 some_string 并移出函数
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string // 返回并移出函数
}

// ==================== 引用和借用 ====================

/// 引用 (References)
/// 引用允许使用值但不获取其所有权
pub fn references() {
    println!("\n=== 引用 ===");
    
    let s1 = String::from("hello");
    let len = calculate_length(&s1); // &s1 创建一个指向 s1 的引用
    
    println!("'{}' 的长度是 {}", s1, len); // s1 仍然有效
}

fn calculate_length(s: &String) -> usize {
    s.len()
} // s 离开作用域，但因为它不拥有所有权，不会有任何影响

/// 可变引用 (Mutable References)
/// 可变引用允许修改借用的值
pub fn mutable_references() {
    println!("\n=== 可变引用 ===");
    
    let mut s = String::from("hello");
    println!("修改前: {}", s);
    
    change(&mut s);
    println!("修改后: {}", s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

/// 可变引用的限制
pub fn mutable_reference_rules() {
    println!("\n=== 可变引用的限制 ===");
    
    let mut s = String::from("hello");
    
    // 规则1: 在特定作用域中，只能有一个可变引用
    let r1 = &mut s;
    println!("可变引用1: {}", r1);
    // let r2 = &mut s; // ❌ 错误: 不能同时有两个可变引用
    
    // 规则2: 不能在拥有不可变引用的同时拥有可变引用
    let s2 = String::from("hello");
    let r1 = &s2;
    let r2 = &s2;
    println!("不可变引用: {}, {}", r1, r2);
    // let r3 = &mut s2; // ❌ 错误: 已经有不可变引用
    
    // 引用的作用域从声明开始到最后一次使用结束
    let mut s3 = String::from("hello");
    let r1 = &s3;
    let r2 = &s3;
    println!("{} and {}", r1, r2);
    // r1 和 r2 在这之后不再使用
    
    let r3 = &mut s3; // ✅ 没问题，r1 和 r2 已经结束使用
    println!("{}", r3);
}

/// 悬垂引用 (Dangling References)
/// Rust 编译器保证不会出现悬垂引用
pub fn no_dangling_references() {
    println!("\n=== 悬垂引用 ===");
    
    // let reference_to_nothing = dangle(); // ❌ 编译错误
    let string = no_dangle();
    println!("有效的字符串: {}", string);
}

// fn dangle() -> &String { // ❌ 返回引用，但值会被销毁
//     let s = String::from("hello");
//     &s
// } // s 离开作用域并被销毁，引用指向无效内存

fn no_dangle() -> String {
    let s = String::from("hello");
    s // 直接返回 String，转移所有权
}

// ==================== 切片类型 ====================

/// 切片 (Slices)
/// 切片允许引用集合中的一段连续元素序列
pub fn string_slices() {
    println!("\n=== 字符串切片 ===");
    
    let s = String::from("hello world");
    
    let hello = &s[0..5]; // 或 &s[..5]
    let world = &s[6..11]; // 或 &s[6..]
    
    println!("完整字符串: {}", s);
    println!("第一个词: {}", hello);
    println!("第二个词: {}", world);
    
    let whole = &s[..]; // 整个字符串的切片
    println!("整个切片: {}", whole);
    
    // 实际应用: 获取第一个单词
    let first = first_word(&s);
    println!("第一个单词: {}", first);
}

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();
    
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    
    &s[..]
}

/// 字符串字面量是切片
pub fn string_literals_are_slices() {
    println!("\n=== 字符串字面量是切片 ===");
    
    let s = "Hello, world!"; // s 的类型是 &str
    println!("字符串字面量类型: &str");
    println!("值: {}", s);
    
    // &str 是不可变引用
}

/// 改进的 first_word 函数
pub fn improved_first_word() {
    println!("\n=== 改进的 first_word ===");
    
    fn first_word(s: &str) -> &str {
        let bytes = s.as_bytes();
        
        for (i, &item) in bytes.iter().enumerate() {
            if item == b' ' {
                return &s[0..i];
            }
        }
        
        &s[..]
    }
    
    let my_string = String::from("hello world");
    let word = first_word(&my_string[..]); // String 的切片
    println!("从 String 获取: {}", word);
    
    let my_string_literal = "hello world";
    let word = first_word(my_string_literal); // 直接传递字符串字面量
    println!("从字面量获取: {}", word);
}

/// 其他类型的切片
pub fn other_slices() {
    println!("\n=== 其他切片 ===");
    
    let a = [1, 2, 3, 4, 5];
    let slice = &a[1..3]; // 数组切片
    
    println!("数组: {:?}", a);
    println!("切片: {:?}", slice);
    assert_eq!(slice, &[2, 3]);
}

/// 所有权最佳实践
pub fn ownership_best_practices() {
    println!("\n=== 所有权最佳实践 ===");
    
    println!("1. 尽可能使用引用而不是获取所有权");
    println!("2. 优先使用不可变引用");
    println!("3. 只在需要修改时使用可变引用");
    println!("4. 使用切片访问部分数据");
    println!("5. 理解何时会发生移动");
}

/// 主函数 - 演示所有功能
#[allow(dead_code)]
pub fn main() {
    println!("╔════════════════════════════════════════╗");
    println!("║   Rust 所有权教程                      ║");
    println!("╚════════════════════════════════════════╝");
    
    variable_scope();
    string_type();
    move_semantics();
    clone_data();
    copy_trait();
    ownership_and_functions();
    return_values_and_ownership();
    references();
    mutable_references();
    mutable_reference_rules();
    no_dangling_references();
    string_slices();
    string_literals_are_slices();
    improved_first_word();
    other_slices();
    ownership_best_practices();
    
    println!("\n✅ 所有权教程完成！");
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_calculate_length() {
        let s = String::from("hello");
        assert_eq!(calculate_length(&s), 5);
    }
    
    #[test]
    fn test_string_slice() {
        let s = String::from("hello world");
        assert_eq!(&s[0..5], "hello");
        assert_eq!(&s[6..11], "world");
    }
}

